package com.xinqi.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xinqi.dto.BlogCommentDto;
import com.xinqi.entity.Blog;
import com.xinqi.entity.BlogComment;
import com.xinqi.mapper.BlogCommentMapper;
import com.xinqi.service.BlogCommentService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

/**
 * @author xin麒
 * @date 2023/6/25 22:34
 */
@Service
public class BlogCommentServiceImpl extends ServiceImpl<BlogCommentMapper, BlogComment> implements BlogCommentService {

    @Override
    public List<BlogComment> getPageByLimitedAndPage(Page<BlogComment> pageParam) {
        Page<BlogComment> blogPage = baseMapper.selectPage(pageParam, null);
        List<BlogComment> records = blogPage.getRecords();
        return records;
    }

    @Override//通过博客id获取当前博客的所有评论。评论肯定是确定了的，而且有子评论，情况较为复杂，下面是自己的一个实现
    public List<BlogCommentDto> getTreeByBlogId(Long blogId) {
        //1、首先获取根评论链表rootBlogComments
        List<BlogComment> rootBlogComments = getBlogCommentsByBlogIdWithDeepOrderByAsc(blogId, 0);
        //2、再次将首先获取根评论链表rootBlogComments里的BlogComment封装到dto里面，因为BlogComment没有子评论链表属性：nodes
        List<BlogCommentDto> rootBlogDtoComments = getBlogCommentDtoListByBlogComments(rootBlogComments);
        //3、往根评论链表rootBlogDtoComments添加子评论，递归添加，每次递归则将子评论作为递归函数的根评论
        fillRootCommentsByBlogIdWithDeepOrderByAsc(blogId,1,rootBlogDtoComments);
        //4、返回结果
        return rootBlogDtoComments;
    }

    //往根节点评论添加子评论
    private void fillRootCommentsByBlogIdWithDeepOrderByAsc(Long blogId,int deep,List<BlogCommentDto> rootBlogComments) {
        //先获取下一级评论列表
        List<BlogComment> sonBlogComments = getBlogCommentsByBlogIdWithDeepOrderByAsc(blogId, deep);
        //判断子评论链表是否存在
        if (sonBlogComments == null || sonBlogComments.size() == 0) return;
        //逐一封装为dto
        List<BlogCommentDto> sonCommentDtoList = getBlogCommentDtoListByBlogComments(sonBlogComments);
        //根评论字典：作用定位root评论的索引
        HashMap<Long,Integer> rootIndexMap = getIndex(rootBlogComments);

        //往根评论里添加子评论
        for (BlogCommentDto blogCommentDto : sonCommentDtoList) {
            //先找到根节点评论到底是哪一个
            Long answerId = blogCommentDto.getAnswerId();

            //找到rootBlogComments里的定位
            int index = rootIndexMap.get(answerId);

            //通过rootIndexMap这个根评论字典寻找root.commentId=ansId的根评论
            BlogCommentDto rootBlogComment = rootBlogComments.get(index);

            List<BlogComment> nodes = rootBlogComment.getNodes();
            if (nodes == null) {
                nodes = new LinkedList<>();
                rootBlogComment.setNodes(nodes);
            }
            //添加子评论
            nodes.add(blogCommentDto);

        }

        //每次递归则将子评论链表sonCommentDtoList作为递归函数的根评论链表
        fillRootCommentsByBlogIdWithDeepOrderByAsc(blogId,deep + 1,sonCommentDtoList);

    }

    //根评论的定位字典
    private HashMap<Long, Integer> getIndex(List<BlogCommentDto> blogComments) {
        HashMap<Long, Integer> indexMap = new HashMap<>();
        for(int index = 0 ; index < blogComments.size();index++){
            indexMap.put(blogComments.get(index).getCommentUserId(),index);
        }
        return indexMap;
    }

    private List<BlogComment> getBlogCommentsByBlogIdWithDeepOrderByAsc(Long blogId,int deep){
        LambdaQueryWrapper<BlogComment> queryWrapper = new LambdaQueryWrapper<>();//asc升序，从小到大
        queryWrapper.eq(BlogComment::getBlogId,blogId).eq(BlogComment::getDeep,deep).orderByAsc(BlogComment::getCreateTime);
        return baseMapper.selectList(queryWrapper);
    }

    //将BlogComments封装成为BlogCommentDto
    private List<BlogCommentDto> getBlogCommentDtoListByBlogComments(List<BlogComment> blogComments) {
        List<BlogCommentDto> blogCommentDtoList = new ArrayList<>(blogComments.size());
        for (BlogComment blogComment :blogComments) {
            BlogCommentDto blogCommentDto = new BlogCommentDto();
            BeanUtils.copyProperties(blogComment, blogCommentDto);
            blogCommentDtoList.add(blogCommentDto);
        }
        return blogCommentDtoList;
    }
}
